package com.skeeey.aim.service.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.skeeey.aim.service.dao.DaoException;
import com.skeeey.aim.service.dao.TempleteDao;

@SuppressWarnings("unchecked")
public class TempleteDaoImpl<T extends Serializable, PK extends Serializable>
		extends HibernateDaoSupport implements TempleteDao<T, PK> {
	
	private Class<T> entityClass;
	
	public Class<T> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	@Override
	public T get(PK id) {
		// Get object by id. If not find, return null.
		return (T) this.getHibernateTemplate().get(entityClass, id);
	}
	
	@Override
	public T load(PK id) throws DaoException {
		try {
			return (T) this.getHibernateTemplate().load(entityClass, id);
		} catch (DataAccessException e) {
			throw new DaoException("load [" + entityClass.getName() + "] by <" + id + "> failed!!", e);
		}
	}
	
	@Override
	public void update(T entity) throws DaoException {
		try {
			this.getHibernateTemplate().update(entity);
		} catch (DataAccessException e) {
			throw new DaoException("update [" + entityClass.getName() + "] failed!!", e);
		}
	}
	
	@Override
	public void save(T entity) throws DaoException {
		try {
			this.getHibernateTemplate().save(entity);
		} catch (DataAccessException e) {
			throw new DaoException("save [" + entityClass.getName() + "] failed!!", e);
		}
	}

	@Override
	public void saveOrUpdate(T entity) throws DaoException {
		try {
			this.getHibernateTemplate().saveOrUpdate(entity);
		} catch (DataAccessException e) {
			throw new DaoException("save or update [" + entityClass.getName() + "] failed!!", e);
		}
	}
	
	@Override
	public void saveOrUpdateAll(Collection<T> entities) throws DaoException {
		try {
			this.getHibernateTemplate().saveOrUpdateAll(entities);
		} catch (DataAccessException e) {
			throw new DaoException("save or update entities [" + entityClass.getName() + "] failed!!", e);
		}
	}
	
	@Override
	public void delete(T entity) throws DaoException {
		try {
			this.getHibernateTemplate().delete(entity);
		} catch (DataAccessException e) {
			throw new DaoException("delete [" + entityClass.getName() + "] failed!!", e);
		}
	}

	@Override
	public void deleteAll(Collection<T> entities) throws DaoException {
		try {
			this.getHibernateTemplate().deleteAll(entities);
		} catch (DataAccessException e) {
			throw new DaoException("delete entities [" + entityClass.getName() + "] failed!!", e);
		}
	}

	@Override
	public void deleteByKey(PK id) throws DaoException {
		try {
			this.getHibernateTemplate().delete(this.getHibernateTemplate().load(entityClass, id));
		} catch (DataAccessException e) {
			throw new DaoException("delete [" + entityClass.getName() + "] by <" + id + "> failed!!", e);
		}
	}
	
	@Override
	public List<T> list() {
		DetachedCriteria criteria = DetachedCriteria.forClass(this.entityClass);
		return this.getHibernateTemplate().findByCriteria(criteria);
	}

	@Override
	public List<T> query(final String hql) throws DaoException {
		try {
			return this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						@Override
						public Object doInHibernate(Session session) throws HibernateException, SQLException {
							return session.createQuery(hql).list();
						}
					});
		} catch (DataAccessException e) {
			throw new DaoException("query failed!! [" + hql + "]", e);
		}
	}
}
